package com.eian.boot.crypto.config;

import com.eian.boot.crypto.constant.CryptoConstants;
import com.eian.boot.crypto.model.KeyPairInfo;
import com.eian.boot.crypto.utils.KeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 加密配置初始化器
 * <p>
 * 在应用启动时检测配置文件是否存在，如果不存在则自动生成默认配置
 *
 * @author eian
 */
@Slf4j
public class CryptoConfigInitializer implements ApplicationRunner {

    private final CryptoProperties cryptoProperties;

    public CryptoConfigInitializer(CryptoProperties cryptoProperties) {
        this.cryptoProperties = cryptoProperties;
    }

    @Override
    public void run(ApplicationArguments args) {
        if (!cryptoProperties.isAutoGenerateConfig()) {
            log.info("自动生成配置文件功能已禁用");
            return;
        }

        String configFilePath = cryptoProperties.getConfigFile();
        Path configPath = Paths.get(configFilePath);

        // 检查配置文件是否存在
        if (Files.exists(configPath)) {
            log.info("加密配置文件已存在: {}", configPath.toAbsolutePath());
            return;
        }

        // 生成配置文件
        try {
            generateConfigFile(configPath);
            log.info("成功生成加密配置文件: {}", configPath.toAbsolutePath());
            log.warn("警告：配置文件包含敏感密钥信息，请妥善保管！建议将该文件添加到 .gitignore");
        } catch (Exception e) {
            log.error("生成加密配置文件失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 生成配置文件
     */
    private void generateConfigFile(Path configPath) throws IOException {
        // 确保父目录存在
        Path parentDir = configPath.getParent();
        if (parentDir != null && !Files.exists(parentDir)) {
            Files.createDirectories(parentDir);
        }

        // 生成密钥
        String aesKey = KeyUtils.generateAESKey(CryptoConstants.Defaults.AES_KEY_SIZE);
        String sm4Key = KeyUtils.generateSM4Key();
        KeyPairInfo rsaKeyPair = KeyUtils.generateRSAKeyPair(CryptoConstants.Defaults.RSA_KEY_SIZE);
        KeyPairInfo sm2KeyPair = KeyUtils.generateSM2KeyPair();
        String aesIv = KeyUtils.generateIV(CryptoConstants.IvLength.AES_CBC);
        String sm4Iv = KeyUtils.generateIV(CryptoConstants.IvLength.SM4_CBC);

        // 生成配置文件内容
        String configContent = generateConfigContent(aesKey, sm4Key, rsaKeyPair, sm2KeyPair, aesIv, sm4Iv);

        // 写入文件
        Files.write(configPath, configContent.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 生成配置文件内容
     */
    private String generateConfigContent(String aesKey, String sm4Key,
                                         KeyPairInfo rsaKeyPair, KeyPairInfo sm2KeyPair,
                                         String aesIv, String sm4Iv) {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        return String.format("""
                        ###############################################
                        # 加密配置文件 - 自动生成于 %s
                        # 警告：此文件包含敏感密钥信息，请妥善保管
                        # 建议：生产环境请将此文件添加到 .gitignore
                        ###############################################
                        
                        eian:
                          crypto:
                            # 是否启用加密组件
                            enabled: true
                        
                            # 默认加密算法（AES_CBC/AES_GCM/SM4_CBC/RSA/SM2）
                            default-algorithm: AES_CBC
                        
                            # 是否在启动时自动生成配置文件（如果不存在）
                            auto-generate-config: true
                        
                            # AES 配置
                            aes:
                              # 密钥（Base64编码，256位）
                              key: %s
                              # 密钥长度（128/192/256）
                              key-size: 256
                              # 初始化向量 IV（Base64编码，可选）
                              iv: %s
                        
                            # RSA 配置
                            rsa:
                              # 公钥（Base64编码）
                              public-key: %s
                              # 私钥（Base64编码）
                              private-key: %s
                              # 密钥长度（1024/2048/4096）
                              key-size: 2048
                        
                            # SM4 配置（国密）
                            sm4:
                              # 密钥（Base64编码，128位）
                              key: %s
                              # 初始化向量 IV（Base64编码，可选）
                              iv: %s
                        
                            # SM2 配置（国密）
                            sm2:
                              # 公钥（Base64编码）
                              public-key: %s
                              # 私钥（Base64编码）
                              private-key: %s
                        
                        ###############################################
                        # 使用说明：
                        # 1. 对称加密（AES/SM4）适用于大量数据加密，速度快
                        # 2. 非对称加密（RSA/SM2）适用于密钥交换和数字签名
                        # 3. 生产环境建议定期更换密钥
                        # 4. 国密算法（SM2/SM4）适用于需要满足国密合规要求的场景
                        ###############################################
                        """,
                timestamp,
                aesKey,
                aesIv,
                rsaKeyPair.getPublicKey(),
                rsaKeyPair.getPrivateKey(),
                sm4Key,
                sm4Iv,
                sm2KeyPair.getPublicKey(),
                sm2KeyPair.getPrivateKey()
        );
    }
}

